import configparser
import logging
import os
from typing import List

from PyQt5.QtCore import *
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import *
from PyQt5.QtWidgets import *

from data.defines import *
from data.gisutils import *

file_path_mac = os.getcwd() + '/'
file_path_win = os.getcwd() + '\\'


# 地图相关的类


# 编辑航线的窗体
class EditRoute(QDialog):
    SigDelRoute = pyqtSignal(int)  # 删除航点，参数是index，从0开始的
    SigSaveRoute = pyqtSignal(int, float, float, int, int)  # 保存航点，返回index, lon, lat, alt, status

    def __init__(self):
        super().__init__()
        self.setModal(True)
        self.no = None
        self.initui()

    def initui(self):
        main_box = QVBoxLayout()

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(QLabel('经度: '))
        self.edit_lon = QLineEdit()
        self.edit_lon.setFixedWidth(150)
        hbox.addWidget(self.edit_lon)
        hbox.addStretch(1)
        main_box.addLayout(hbox)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(QLabel('纬度: '))
        self.edit_lat = QLineEdit()
        self.edit_lat.setFixedWidth(150)
        hbox.addWidget(self.edit_lat)
        hbox.addStretch(1)
        main_box.addLayout(hbox)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(QLabel('高度: '))
        self.edit_alt = QLineEdit()
        self.edit_alt.setFixedWidth(150)
        hbox.addWidget(self.edit_alt)
        hbox.addStretch(1)
        main_box.addLayout(hbox)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(QLabel('状态: '))
        self.edit_state = QLineEdit()
        self.edit_state.setFixedWidth(150)
        hbox.addWidget(self.edit_state)
        hbox.addStretch(1)
        main_box.addLayout(hbox)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        btn = QPushButton('保存')
        btn.clicked.connect(self.click_save)
        hbox.addWidget(btn)
        btn = QPushButton('删除')
        btn.clicked.connect(self.click_del)
        hbox.addWidget(btn)
        hbox.addStretch(1)
        main_box.addLayout(hbox)

        self.setLayout(main_box)

    def show_route(self, route):
        self.no = route.no
        self.edit_lon.setText('%.7f' % route.lon)
        self.edit_lat.setText('%.7f' % route.lat)
        self.edit_alt.setText(str(route.alt))
        self.edit_state.setText(str(route.status))

    def click_save(self):
        lon = self.edit_lon.text().strip()
        lat = self.edit_lat.text().strip()
        alt = self.edit_alt.text().strip()
        state = self.edit_state.text().strip()
        if len(lon) == 0 or len(lat) == 0 or len(alt) == 0 or len(state) == 0:
            QMessageBox.information(self, 'info', '请输入数值!', QMessageBox.Ok)
            return
        self.SigSaveRoute.emit(self.no - 1, float(lon), float(lat), int(alt), int(state))
        # 关闭窗口
        self.close()

    def click_del(self):
        self.SigDelRoute.emit(self.no - 1)
        self.close()


# pyqt和web的交互
class WebInteractObject(QObject):
    sigFromWebGetMouseLonLat = pyqtSignal(float, float)  # 从地图获取到鼠标位置对应经纬度的信号
    SigToWebPlaneLoc = pyqtSignal(float, float, float)  # 向网页发送飞机位置信息以及机头朝向
    SigToWebSetCenter = pyqtSignal(float, float)  # 设置地图中心视角，传入经纬度
    SigToWebEnableClick = pyqtSignal(bool)  # 是否允许地图点击事件
    SigToWebAddRoutes = pyqtSignal(list)  # 向地图添加航线
    SigToWebAddTaxiRoutes = pyqtSignal(list)  # 向地图添加航线
    SigToWebClearTrace = pyqtSignal()  # 删除飞机轨迹线
    SigToWebToFitView = pyqtSignal()  # 显示所有的点
    # 显示跑道到轨道上， 参数是数组，数组结构为[起点A侧点，终点A侧点，起点B侧点，终点B侧点，起点，终点]，每个元素还是数组，结构为[经度，纬度]
    # 坐标系是wgs84
    SigToWebUpdateRunWay = pyqtSignal(list)
    SigToWebUpdateSeondRunWay = pyqtSignal(list)  # 第二条跑道信息显示接口

    SigFromWebAddRoute = pyqtSignal(float, float)  # 收到地图上添加的航点，参数是经度，纬度
    SigFromWebUpdateRoute = pyqtSignal(int, float, float, int, int)  # 修改航点信息，参数是：从0起序号， 经度，纬度，高度，状态字
    SigFromWebUpdateTaxiRoute = pyqtSignal(int,float,float)  #修改滑行航点信息，参数：序号、经度、纬度
    SigFromWebEditRoute = pyqtSignal(int)  # 收到地图编辑航点的请求，参数是航点的序号
    SigFromWebFinishLoad = pyqtSignal()  # 地图加载成功的消息

    def __init__(self, parent=None):
        super().__init__(parent)

    @pyqtSlot(float, float)
    def web_addroute(self, lon, lat):
        self.SigFromWebAddRoute.emit(lon, lat)

    @pyqtSlot(int, float, float, int, int)
    def web_updateroute(self, index, lon, lat, alt, state):
        self.SigFromWebUpdateRoute.emit(index, lon, lat, alt, state)

    @pyqtSlot(int, float, float)
    def web_update_taxi_route(self, index, lon, lat):
        self.SigFromWebUpdateTaxiRoute.emit(index, lon, lat)

    @pyqtSlot(int)
    def web_editroute(self, index):
        self.SigFromWebEditRoute.emit(index)

    @pyqtSlot()
    def web_finishload(self):
        self.SigFromWebFinishLoad.emit()

    @pyqtSlot(float, float)
    def web_on_mouseMove(self, lon, lat):
        # print("mouse at (" + str(lon) + "," + str(lat) + ")")
        self.sigFromWebGetMouseLonLat.emit(lon, lat)


# 地图控件
class GCSMap(QWidget):
    def __init__(self, *args, **kwargs):
        text = kwargs.pop("text", "")
        super(GCSMap, self).__init__(*args, **kwargs)

        self.timer = QTimer()  # 创建窗口定时器，用于处理周期任务
        self.timer.timeout.connect(self._period_update_plane_pos)

        self.load_finish_timer = QTimer()
        self.load_finish_timer.timeout.connect(self.load_finish_timer_process)
        self.InitUI()

    def InitUI(self):

        self.route_list = []  # 存储航路信息的列表
        self.taxi_route_list = []
        # self.parser = DataHandler()
        # self.parser.receiveDataA.connect(self.sig_tela)
        # self.parser.receiveDataC.connect(self.sig_telc)

        self.editview = EditRoute()
        self.editview.SigSaveRoute.connect(self.sig_edit_save)
        self.editview.SigDelRoute.connect(self.sig_edit_del)  # 航路编辑窗口

        self.webview = QWebEngineView()
        # channel需要传入webview作为参数，不然无效
        self.channel = QWebChannel(self.webview)
        # interact_obj必须使用self引用，不然会因为被释放而崩溃
        self.interact_obj = WebInteractObject()
        self.interact_obj.SigFromWebAddRoute.connect(self.sig_web_add_dot)
        self.interact_obj.SigFromWebUpdateRoute.connect(self.sig_web_updateroute)
        self.interact_obj.SigFromWebUpdateTaxiRoute.connect(self.sig_web_update_taxi_route)
        self.interact_obj.SigFromWebEditRoute.connect(self.sig_editroute)
        self.interact_obj.SigFromWebFinishLoad.connect(self.sig_web_finishload)
        self.interact_obj.sigFromWebGetMouseLonLat.connect(self.mouse_lonlat_get)
        self.channel.registerObject('interactObj', self.interact_obj)
        self.webview.page().setWebChannel(self.channel)

        path = os.getcwd()
        # print('map thread:', threading.current_thread())
        if path.startswith('/'):
            url = 'file://' + path + '/resources/openlayers_map/index.html'
            # url = 'file://' + path + '/resources/openlayers_map/index.html'
        else:
            path = path.replace('\\', '/')
            url = 'file:///' + path + '/resources/openlayers_map/index.html'
            # url = 'file:///' + path + '/resources/openlayers_map/index.html'
        # print(url)
        self.webview.load(QUrl(url))
        # self.webview.show()

        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        hbox.addWidget(self.webview)
        self.setLayout(hbox)

        btn = QPushButton('清除轨迹', self)
        btn.setStyleSheet("color: rgb(0, 0, 0);background-color: rgb(255, 255, 255);")
        btn.move(1300, 10)
        btn.clicked.connect(self.click_clear_trace)

        # self.mouseMoveEvent(print("xxxxxxxxx"))
        # self.bg_label = QLabel(self)
        # self.bg_label.setStyleSheet("border:1px white;border-radius:3px;background-color: #FFFFFF;color: #151515;padding:2px 4px;")
        # self.bg_label.move(12, 40)
        # self.bg_label.setMinimumSize(140, 31)
        # setBackColor(self.bg_label, 255, 255, 255)

        # self.label_model = QLabel('当前模式：', self.bg_label)
        # self.label_model.move(5, 5)
        # self.label_model.setMinimumSize(160, 20)
        # setBackColor(self.label_model, 255, 255, 255, 0)
        # setTextColor(self.label_model, 21, 21, 21)

        # self.label_on_taxi = QLabel('', self.bg_label)
        # self.label_on_taxi.move(5, 35)
        # self.label_on_taxi.setMinimumSize(140, 20)
        # setBackColor(self.label_on_taxi, 255, 255, 255, 0)
        # setTextColor(self.label_on_taxi, 21, 21, 21)

        # self.show_runway()
        # self.show()
        # self.test_plane()
    def webview_reload(self):
        """
        重载刷新地图页面
        :return:
        """
        try:
            self.webview.reload()
        except Exception as err:
            logging.error(repr(err))

    def mouse_lonlat_get(self, lon, lat):
        # print("mouse at (" + str(lon) + "," + str(lat) + ")")
        pass

    def set_plane(self, lon, lat, heading):
        self.planelon = lon
        self.planelat = lat
        self.angle = heading

    def _period_update_plane_pos(self):
        # 更新飞机数据，测试显示内容
        # self.planelon += 0.0000009
        # self.planelat += 0.0000009
        # self.angle += 1
        try:
            self.interact_obj.SigToWebPlaneLoc.emit(self.planelon, self.planelat, self.angle)
        except Exception as err:
            logging.error(repr(err))

    def set_view_at_plane(self):
        try:
            self.interact_obj.SigToWebSetCenter.emit(self.planelon, self.planelat)
        except Exception as err:
            logging.error(repr(err))

    def click_clear_trace(self):
        try:
            self.interact_obj.SigToWebClearTrace.emit()
        except Exception as err:
            logging.error(repr(err))

    def set_view_at_route(self):
        try:
            self.interact_obj.SigToWebToFitView.emit()
        except Exception as err:
            logging.error(repr(err))

    def enter_addroute_state(self, on, clear=True):
        try:
            if on:
                # 绘制航线
                self.interact_obj.SigToWebEnableClick.emit(True)
            else:
                # 取消绘制，不可以打点
                self.interact_obj.SigToWebEnableClick.emit(False)
            if clear:
                self.route_list = []
                self.show_current_routes_tomap()
        except Exception as err:
            logging.error(repr(err))

    def show_current_routes_tomap(self):
        arr = []
        for route in self.route_list:
            # arr.append([route.lon, route.lat, route.alt, route.state])
            arr.append({'lon': route.lon, 'lat': route.lat, 'alt': route.alt, 'state': route.status})
        # print(arr)
        try:
            self.interact_obj.SigToWebAddRoutes.emit(arr)
        except Exception as err:
            logging.error(repr(err))

    def show_taxi_routes2map(self, taxi_route_list: List[RouteInfo]):
        arr = []
        self.taxi_route_list = taxi_route_list
        for route in taxi_route_list:
            # arr.append([route.lon, route.lat, route.alt, route.state])
            arr.append({'lon': route.lon, 'lat': route.lat, 'alt': route.alt, 'state': route.status})
        # print(arr)
        try:
            self.interact_obj.SigToWebAddTaxiRoutes.emit(arr)
        except Exception as err:
            logging.error(repr(err))

    def show_runway(self):
        # self.show_runway_info(118.762834, 31.831589, 118.762034, 31.831589, 90)
        # self.interact_obj.SigToWebSetCenter.emit(118.762034, 31.831589)
        # 跑道更新了，重新显示跑道位置
        # 读取跑道信息
        current = os.getcwd()
        if current.startswith('/'):
            filename = file_path_mac + runway_set_filename
        else:
            filename = file_path_win + runway_set_filename
        if os.path.exists(filename):
            cf = configparser.ConfigParser()
            try:
                cf.read(filename)
                start_lon = cf.get(FILE_LEVEL_RUNWAY, FILE_ITEM_RUNWAY_START_LON, fallback=None)
                start_lat = cf.get(FILE_LEVEL_RUNWAY, FILE_ITEM_RUNWAY_START_LAT, fallback=None)
                end_lon = cf.get(FILE_LEVEL_RUNWAY, FILE_ITEM_RUNWAY_END_LON, fallback=None)
                end_lat = cf.get(FILE_LEVEL_RUNWAY, FILE_ITEM_RUNWAY_END_LAT, fallback=None)
                width = cf.get(FILE_LEVEL_RUNWAY, FILE_ITEM_RUNWAY_WIDTH, fallback=None)
                # 此处获取的是字符串变量，使用时需要转换为浮点数
                if (start_lon is not None) and \
                        (start_lat is not None) and \
                        (end_lon is not None) and \
                        (end_lat is not None) and \
                        (width is not None):
                    # 确定轨道上的点
                    # print(float(start_lat))
                    # self.interact_obj.SigToWebSetCenter.emit(float(start_lon), float(start_lat))
                    self.show_runway_info(float(start_lon), float(start_lat), float(end_lon), float(end_lat),
                                          float(width))

            except BaseException as e:
                pass

    def show_runway_info(self, lon_start, lat_start, lon_end, lat_end, width):
        # 确定轨道上的点
        point_list = cal_runway_param(lon_start, lat_start, lon_end,
                                      lat_end, width)
        # 加上中间线的点
        point_list.append([lon_start, lat_start])
        point_list.append([lon_end, lat_end])
        # 地图绘制跑道
        arr = []
        for dot in point_list:
            # arr.append([route.lon, route.lat, route.alt, route.state])
            arr.append({'lon': dot[0], 'lat': dot[1], 'alt': 0, 'state': 0})
        # print(arr)
        try:
            self.interact_obj.SigToWebSetCenter.emit(lon_start, lat_start)
            self.interact_obj.SigToWebUpdateRunWay.emit(arr)
        except Exception as err:
            logging.error(repr(err))

    def show_second_runway_info(self, lon_start, lat_start, lon_end, lat_end, width):
        # 确定轨道上的点
        point_list = util_calc_runway_param(lon_start, lat_start, lon_end,
                                            lat_end, width)
        # 加上中间线的点
        point_list.append([lon_start, lat_start])
        point_list.append([lon_end, lat_end])
        # 地图绘制跑道
        arr = []
        for dot in point_list:
            # arr.append([route.lon, route.lat, route.alt, route.state])
            arr.append({'lon': dot[0], 'lat': dot[1], 'alt': 0, 'state': 0})
        # print(arr)
        try:
            self.interact_obj.SigToWebUpdateSeondRunWay.emit(arr)
        except Exception as err:
            logging.error(repr(err))

    # 地图加载成功之后调用
    def sig_web_finishload(self):
        self.set_plane(118.762834, 31.831589, 0)
        self.timer.start(100)
        self.load_finish_timer.start(1000)

    def load_finish_timer_process(self):  # 此定时器只在加载成功时调用一次
        self.show_runway()
        self.load_finish_timer.stop()

    def sig_show_route(self, route_list):
        # print("sig_show_route called!")
        self.route_list = route_list
        self.show_current_routes_tomap()

    def sig_web_add_dot(self, lon, lat):
        """
        在web页面中添加航点
        :param lon:新增航点的经度 -180 ~ 180 deg
        :param lat:新增航点的纬度 -90 ~ 90 deg
        :return:
        """
        p = RouteInfo()
        p.no = len(self.route_list) + 1
        p.lon = lon
        p.lat = lat
        p.alt = 0
        p.status = 0
        self.route_list.append(p)

    def sig_web_updateroute(self, index, lon, lat, alt, state):
        # 修改航点信息
        if index < len(self.route_list):
            p = self.route_list[index]
            p.lon = lon
            p.lat = lat
            p.alt = alt
            p.status = state

    def sig_web_update_taxi_route(self, index, lon, lat):
        # 修改滑行航点信息
        if index < len(self.taxi_route_list):
            p = self.taxi_route_list[index]
            p.lon = lon
            p.lat = lat
            p.radious = 0


    def sig_editroute(self, index):
        if index < len(self.route_list):
            self.editview.show_route(self.route_list[index])
            self.editview.show()

    def sig_edit_del(self, index):
        # 删除航点
        if index < len(self.route_list):
            del self.route_list[index]
            for i in range(index, len(self.route_list)):
                p = self.route_list[i]
                p.no -= 1
            # 通知地图改变位置
            self.show_current_routes_tomap()

    def sig_edit_save(self, index, lon, lat, alt, state):
        # 编辑航点
        if index < len(self.route_list):
            p = self.route_list[index]
            refresh = (str(lon) != str(p.lon) or str(lat) != str(p.lat))
            p.lat = lat
            p.lon = lon
            p.alt = alt
            p.status = state
            if refresh:
                # 通知地图mark改变位置
                self.show_current_routes_tomap()

    # def sig_tela(self, data):
    #     if data.on_taxi == 1:
    #         self.label_model.setText('当前模式：%s' % data.flight_mode_name())
    #         self.label_on_taxi.setText('滑行状态')
    #         self.bg_label.setMinimumSize(190, 65)
    #     else:
    #         self.label_model.setText('当前模式：%s' % data.flight_mode_name())
    #         self.label_on_taxi.setText('')
    #         self.bg_label.setMinimumSize(160, 31)

    # def sig_telc(self, data):
    #     # 更新飞机位置
    #     self.interact_obj.SigToWebPlaneLoc.emit(data.long_fusion, data.late_fusion, data.heading_angle_fusion)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    map_widget = GCSMap()
    map_widget.setObjectName("map_widget")

    map_widget.show()
    # 显示飞机位置
    map_widget.set_plane(118.762834, 31.831589, 270)

    # 进入航线编辑模式 需要在地图加载完成之后调用才能生效
    # map_widget.enter_addroute_state(True)

    # 设置跑道
    # 显示跑道信息 需要在地图加载完成之后调用才能生效
    # map_widget.show_runway_info(118.762834, 31.831589, 118.762034, 31.831589, 90)

    # 显示航线 需要在地图加载完成之后调用才能生效
    # map_widget.sig_web_add_dot(118.762834, 31.831589)
    # map_widget.sig_web_add_dot(118.762934, 31.831589)
    # map_widget.sig_web_add_dot(118.762934, 31.831689)
    # map_widget.sig_web_add_dot(118.762834, 31.831689)
    # map_widget.show_current_routes_tomap()
    sys.exit(app.exec_())
